import threading
import numpy as np
import requests
import hashlib
from sys import argv
from time import time, sleep
# from datetime import datetime

# =======================================================================================================================================
# 全局变量区：

MAX_RETRIES = 3  # 最大尝试次数

# 定义不同场景和季节的数据生成范围
SCENES = {
    "family": {
        "winter": {
            "temperature": (16, 22),  # wintertemperature范围：16°C 到 22°C
            "humidity": (30, 50),  # winterhumidity范围：30% 到 50%
            "fresh_air": (0.5, 1.0),  # winterfresh_air范围：0.5 m³/min 到 1.0 m³/min
            "ozone": (0.019, 0.031),  # winterozone范围：0.01 ppb 到 0.03 ppb
            "nitro_dio": (
                0.017,
                0.032,
            ),  # winternitro_dio含量范围：0.01 ppm 到 0.03 ppm
            "methanal": (
                0.021,
                0.085,
            ),  # wintermethanal含量范围：0.02 mg/m³ 到 0.08 mg/m³
            "pm2_5": (
                15.214,
                40.032,
            ),  # winterpm2_5含量范围：15 μg/m³ 到 40 μg/m³
            "carb_momo": (0.601, 4.054),  # wintercarb_momo含量范围：0.6 ppm 到 4.0 ppm
            "bacteria": (120, 800),  # winterbacteria范围：120 cfu/m³ 到 800 cfu/m³
            "radon": (1.245, 3.519),  # winterradon含量范围：1.2 Bq/m³ 到 3.5 Bq/m³
        },
        "summer": {
            "temperature": (24, 28),  # summertemperature范围：24°C 到 28°C
            "humidity": (40, 70),  # summerhumidity范围：40% 到 70%
            "fresh_air": (1.0, 1.5),  # summerfresh_air范围：1.0 m³/min 到 1.5 m³/min
            "ozone": (0.028, 0.054),  # summerozone范围：0.02 ppb 到 0.05 ppb
            "nitro_dio": (
                0.021,
                0.051,
            ),  # summernitro_dio含量范围：0.02 ppm 到 0.05 ppm
            "methanal": (
                0.032,
                0.112,
            ),  # summermethanal含量范围：0.03 mg/m³ 到 0.1 mg/m³
            "pm2_5": (
                10.012,
                45.564,
            ),  # summerpm2_5含量范围：10 μg/m³ 到 45 μg/m³
            "carb_momo": (0.512, 3.521),  # summercarb_momo含量范围：0.5 ppm 到 3.5 ppm
            "bacteria": (100, 600),  # summerbacteria范围：100 cfu/m³ 到 600 cfu/m³
            "radon": (1.065, 3.041),  # summerradon含量范围：1.0 Bq/m³ 到 3.0 Bq/m³
        },
    },
    "lab": {
        "winter": {
            "temperature": (15, 20),  # wintertemperature范围：15°C 到 20°C
            "humidity": (40, 55),  # winterhumidity范围：40% 到 55%
            "fresh_air": (2.0, 3.0),  # winterfresh_air范围：2.0 m³/min 到 3.0 m³/min
            "ozone": (0.005, 0.015),  # winterozone范围：0.005 ppb 到 0.015 ppb
            "nitro_dio": (
                0.005,
                0.015,
            ),  # winternitro_dio含量范围：0.005 ppm 到 0.015 ppm
            "methanal": (
                0.014,
                0.049,
            ),  # wintermethanal含量范围：0.01 mg/m³ 到 0.04 mg/m³
            "pm2_5": (
                6.140,
                15.001,
            ),  # winterpm2_5含量范围：6 μg/m³ 到 15 μg/m³
            "carb_momo": (0.122, 1.575),  # wintercarb_momo含量范围：0.1 ppm 到 1.5 ppm
            "bacteria": (60, 400),  # winterbacteria范围：60 cfu/m³ 到 400 cfu/m³
            "radon": (0.654, 1.525),  # winterradon含量范围：0.6 Bq/m³ 到 1.5 Bq/m³
        },
        "summer": {
            "temperature": (20, 24),  # summertemperature范围：20°C 到 24°C
            "humidity": (45, 60),  # summerhumidity范围：45% 到 60%
            "fresh_air": (2.5, 4.0),  # summerfresh_air范围：2.5 m³/min 到 4.0 m³/min
            "ozone": (0.018, 0.028),  # summerozone范围：0.01 ppb 到 0.02 ppb
            "nitro_dio": (
                0.017,
                0.028,
            ),  # summernitro_dio含量范围：0.01 ppm 到 0.02 ppm
            "methanal": (
                0.014,
                0.055,
            ),  # summermethanal含量范围：0.01 mg/m³ 到 0.05 mg/m³
            "pm2_5": (
                5.235,
                18.002,
            ),  # summerpm2_5含量范围：5 μg/m³ 到 18 μg/m³
            "carb_momo": (0.185, 1.810),  # summercarb_momo含量范围：0.1 ppm 到 1.8 ppm
            "bacteria": (50, 350),  # summerbacteria范围：50 cfu/m³ 到 350 cfu/m³
            "radon": (0.540, 1.800),  # summerradon含量范围：0.5 Bq/m³ 到 1.8 Bq/m³
        },
    },
    "greenhouse": {
        "winter": {
            "temperature": (15, 25),  # wintertemperature范围：15°C 到 25°C
            "humidity": (45, 75),  # winterhumidity范围：45% 到 75%
            "fresh_air": (1.0, 2.0),  # winterfresh_air范围：1.0 m³/min 到 2.0 m³/min
            "ozone": (0.015, 0.034),  # winterozone范围：0.01 ppb 到 0.03 ppb
            "nitro_dio": (
                0.019,
                0.031,
            ),  # winternitro_dio含量范围：0.01 ppm 到 0.03 ppm
            "methanal": (
                0.010,
                0.041,
            ),  # wintermethanal含量范围：0.01 mg/m³ 到 0.04 mg/m³
            "pm2_5": (
                12.201,
                35.203,
            ),  # winterpm2_5含量范围：12 μg/m³ 到 35 μg/m³
            "carb_momo": (0.201, 2.530),  # wintercarb_momo含量范围：0.2 ppm 到 2.5 ppm
            "bacteria": (120, 700),  # winterbacteria范围：120 cfu/m³ 到 700 cfu/m³
            "radon": (0.650, 2.510),  # winterradon含量范围：0.6 Bq/m³ 到 2.5 Bq/m³
        },
        "summer": {
            "temperature": (20, 30),  # summertemperature范围：20°C 到 30°C
            "humidity": (50, 80),  # summerhumidity范围：50% 到 80%
            "fresh_air": (1.5, 3.0),  # summerfresh_air范围：1.5 m³/min 到 3.0 m³/min
            "ozone": (0.011, 0.041),  # summerozone范围：0.01 ppb 到 0.04 ppb
            "nitro_dio": (
                0.019,
                0.041,
            ),  # summernitro_dio含量范围：0.01 ppm 到 0.04 ppm
            "methanal": (
                0.015,
                0.052,
            ),  # summermethanal含量范围：0.01 mg/m³ 到 0.05 mg/m³
            "pm2_5": (
                10.325,
                38.914,
            ),  # summerpm2_5含量范围：10 μg/m³ 到 38 μg/m³
            "carb_momo": (0.284, 2.857),  # summercarb_momo含量范围：0.2 ppm 到 2.8 ppm
            "bacteria": (100, 750),  # summerbacteria范围：100 cfu/m³ 到 750 cfu/m³
            "radon": (0.549, 2.875),  # summerradon含量范围：0.5 Bq/m³ 到 2.8 Bq/m³
        },
    },
}

# =======================================================================================================================================


# 1.获取单个数据
def get_single_data(scene="family", season="winter", include_meta=True) -> dict:
    data = {}
    meta = {}  # 存储μ和σ信息
    data_ranges = SCENES[scene][season]
    for property_name, value_range in data_ranges.items():
        # μ (均值) = 数据范围两端的平均值
        mean = (value_range[0] + value_range[1]) / 2
        # σ (标准差) = μ 减去一端的大小
        std_dev = mean - value_range[0]
        # 使用正态分布生成数据
        value = np.random.normal(mean, std_dev)
        value = max(value_range[0], min(value, value_range[1]))  # 确保值在范围内
        data[property_name] = round(value, 4)
        
        # 如果需要包含元数据，则添加μ和σ信息
        if include_meta:
            meta[property_name] = {
                "mu": round(mean, 4),      # μ值
                "sigma": round(std_dev, 4) # σ值
            }
    
    result = {"values": data}
    if include_meta:
        result["meta"] = meta
    
    return result


# =======================================================================================================================================


# 2.获取属性单位
def get_unit(property_name):
    units = {
        "temperature": "°C",
        "humidity": "%",
        "fresh_air": "m³/min",
        "ozone": "ppb",
        "nitro_dio": "ppm",
        "methanal": "mg/m³",
        "pm2_5": "μg/m³",
        "carb_momo": "ppm",
        "bacteria": "cfu/m³",
        "radon": "Bq/m³",
    }
    return units.get(property_name, "")


# =======================================================================================================================================


# 3.获取所有参数的μ和σ信息
def get_all_parameters_meta():
    """
    获取所有场景、季节下各参数的μ和σ值
    返回格式：
    {
        "scene": {
            "season": {
                "parameter": {"mu": value, "sigma": value}
            }
        }
    }
    """
    all_meta = {}
    for scene, seasons in SCENES.items():
        all_meta[scene] = {}
        for season, parameters in seasons.items():
            all_meta[scene][season] = {}
            for property_name, value_range in parameters.items():
                # μ (均值) = 数据范围两端的平均值
                mean = (value_range[0] + value_range[1]) / 2
                # σ (标准差) = μ 减去一端的大小
                std_dev = mean - value_range[0]
                
                all_meta[scene][season][property_name] = {
                    "mu": round(mean, 4),
                    "sigma": round(std_dev, 4),
                    "unit": get_unit(property_name)
                }
    return all_meta


# =======================================================================================================================================


# 4.根据数据值判断状态
def judge_data_status(value, mu, sigma):
    """
    根据数据值、μ和σ判断数据状态
    参数:
        value: 实际数据值
        mu: 均值
        sigma: 标准差
    返回:
        "normal": 正常 (1.5σ内)
        "abnormal": 异常 (1.5σ--3σ)
        "error": 错误 (超出3σ)
    """
    deviation = abs(value - mu) / sigma
    
    if deviation <= 1.5:
        return "normal"
    elif deviation <= 3.0:
        return "abnormal"
    else:
        return "error"


# =======================================================================================================================================


# 5.生成请求签名
def generate_signature(device_id, timestamp, secret):
    sign_str = f"{device_id}:{timestamp}:{secret}"
    return hashlib.md5(sign_str.encode()).hexdigest()


# =======================================================================================================================================


# 6.输出数据
def output_data(thread_id, scene, season, device, secret):
    print(f"Thread {thread_id} started for {scene} {season}")

    while True:
        # 生成数据
        data_result = get_single_data(scene, season, include_meta=True)
        
        timestamp = int(time())

        # 构建请求数据
        request_data = {
            "device_id": device,
            "timestamp": timestamp,
            "data": data_result["values"],  # 实际的传感器数据
            "meta": data_result["meta"],    # μ和σ元数据，用于后端判断数据状态
            "signature": generate_signature(device, timestamp, secret),
        }

        # 上传尝试3次
        for _ in range(MAX_RETRIES):
            sleep(2)
            try:
                url = f"{HOST}/data/upload"
                # 上传数据
                response = requests.post(
                    url,
                    json=request_data,
                    timeout=10,
                )
                # 根据业务处理状态（HTTP状态码）进行相应操作
                if response.status_code == 200:  # 成功上传
                    print(f"Thread {thread_id}: 数据上传成功")
                    break
                else:
                    if response.json().get("status") == 15:
                        break

                    print(
                        f"Thread {thread_id}: 上传失败，状态码：{response.json()}，尝试重新上传"
                    )
            except (
                requests.exceptions.ConnectionError,
                requests.exceptions.Timeout,
                requests.exceptions.RequestException,
            ) as e:
                print(f"Thread {thread_id}: 网络连接异常 - {str(e)}，正在重试...")
        else:
            print(f"Thread {thread_id}: 达到最大重试次数，将继续尝试...")


# =======================================================================================================================================

def test_data_status_judgment():
    """
    测试数据状态判断功能的演示函数
    """
    print("=== 数据状态判断功能测试 ===")
    
    # 获取所有参数的μ和σ信息
    all_meta = get_all_parameters_meta()
    print("所有参数的μ和σ信息：")
    print(f"实验室夏季温度参数：{all_meta['lab']['summer']['temperature']}")
    
    # 生成一些测试数据
    scene, season = "lab", "summer"
    data_result = get_single_data(scene, season, include_meta=True)
    
    print(f"\n生成的{scene} {season}数据：")
    for param, value in data_result["values"].items():
        mu = data_result["meta"][param]["mu"]
        sigma = data_result["meta"][param]["sigma"]
        status = judge_data_status(value, mu, sigma)
        print(f"{param}: {value} (μ={mu}, σ={sigma}) -> 状态: {status}")
    
    print("\n=== 测试完成 ===\n")


# =======================================================================================================================================

HOST = "http://127.0.0.1:5000"  # 正式测试时, 才会换成云服务器ip

if __name__ == "__main__":
    # 检查是否运行测试
    if len(argv) > 1 and argv[1] == "test":
        test_data_status_judgment()
        exit()
    
    scene = argv[1] if len(argv) > 1 else "lab"
    season = argv[2] if len(argv) > 2 else "summer"
    DEVICES = {
        "test1": "123456789abc",
        "test2": "1234567890a9",
        "test3": "12345678909a",
    }

    # 创建并启动线程（多线程并发）
    threads = []
    for device, secret in DEVICES.items():
        thread = threading.Thread(
            target=output_data,
            args=(device, scene, season, device, secret),
        )  # 创建线程，启用output_data
        threads.append(thread)
        thread.start()